import json
import sys
import demjson3 as demjson
from click import prompt
from langchain.agents import create_openai_functions_agent, AgentExecutor
from langchain.chains.llm import LLMChain
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_community.utilities import SQLDatabase
import os
import dashscope
import ast

from langchain_core.prompts import PromptTemplate, MessagesPlaceholder, ChatPromptTemplate

from core.llm import get_default_llm
from tools.ppt_tool import log_step


class SqlTool:


    def __init__(self):
        self.db = SQLDatabase.from_uri(f"mysql+pymysql://root:200512@43.142.176.219:3306/teachplatform")
        self.schema = self.db.get_table_info()

        self.llm = get_default_llm()
        self.prompt = ChatPromptTemplate.from_messages([
            ("system", f"""你是一个数据分析师，现有数据进行分析，你有以下注意点：
            
            1.你的所有回答都需要基于现有的数据
            2.生成的回复需要尽可能详细
    

            请根据以下描述生成回复：
            描述: {input}

            生成的SQL查询:

        """),
            ("human", "{input}"),
            MessagesPlaceholder(variable_name="agent_scratchpad")
        ])
        # 创建代理
        self.agent = create_openai_functions_agent(
            llm=self.llm,
            tools=[],
            prompt=self.prompt
        )

        self.agent_executor = AgentExecutor(
            agent=self.agent,
            tools=[],
            verbose=True,
            handle_parsing_errors=True
        )

    def query_database(self,prompt):

        schema = self.db.get_table_info()
        full_prompt = f"""
        你是一个数据库查询助手，你需要根据描述生成一个SQL查询。请勿返回任何解释。
        有以下注意点：
        1.请保证你的返回值可直接交由数据库执行。
        2.请返回一个完整的SQL查询，不要返回任何解释。
        3.你操作的是mysql数据库，注意sql的正确性
        4.不要有任何与sql语法无关的东西
        5.不要使用任何Markdown格式
        6.请严格根据数据库表结构生成sql语句，不要出现数据库中没有的字段
        请根据以下表结构信息进行查询：
        {schema}

        请根据以下描述生成一个SQL查询：
        描述: {prompt}

        生成的SQL查询:
        """
        # 使用新的LangChain API创建chain
        prompt_template = PromptTemplate.from_template(full_prompt)
        # 使用新的RunnableSequence方式创建chain
        chain = prompt_template | self.llm
        # 使用invoke方法并传递参数
        query = chain.invoke({}).content
        print( query)
        result = self.db.run(query)
        print( result)
        return result


    def _clean_json_string(self, text: str) -> str:
        """清理JSON字符串"""
        # 找到第一个完整的JSON对象
        start = text.find('{')
        end = -1
        brace_count = 0
        for i in range(start, len(text)):
            if text[i] == '{':
                brace_count += 1
            elif text[i] == '}':
                brace_count -= 1
                if brace_count == 0:
                    end = i + 1
                    break

        if start == -1 or end == -1:
            raise ValueError("未找到有效的JSON内容")

        json_str = text[start:end]


        # 移除代码块标记和注释
        json_str = json_str.replace('```json', '')
        json_str = json_str.replace('```', '')
        json_str = json_str.replace('/*', '')
        json_str = json_str.replace('*/', '')

        # 添加缺失的逗号
        lines = json_str.split('\n')
        processed_lines = []
        for i, line in enumerate(lines):
            line = line.strip()
            if not line:
                continue

            # 如果不是最后一行且当前行以引号结尾且下一行不是结束标记
            if i < len(lines) - 1 and line.rstrip().endswith('"') and not lines[i + 1].strip().startswith('}') and not \
            lines[i + 1].strip().startswith(']'):
                line += ','

            if line.__contains__("image") and line.rstrip().endswith(","):
                line+=','

            # 如果不是最后一行且当前行以大括号或方括号结尾且下一行不是结束标记
            if i < len(lines) - 1 and (line.rstrip().endswith('}') or line.rstrip().endswith(']')) and not lines[
                i + 1].strip().startswith('}') and not lines[i + 1].strip().startswith(']'):
                line += ','

            processed_lines.append(line)

        json_str = '\n'.join(processed_lines)

        # ✅ 转义英文单引号为 JSON 兼容的格式
        #json_str = json_str.replace("'", "\\'")
        # 替换中文标点为英文标点
        json_str = json_str.replace('，', ',')
        json_str = json_str.replace('：', ':')
        json_str = json_str.replace('“', '"')
        json_str = json_str.replace('”', '"')
        json_str = json_str.replace('’', "'")
        json_str = json_str.replace('‘', "'")
        json_str = json_str.replace('（', '(')
        json_str = json_str.replace('）', ')')

        # 添加缺失的逗号
        lines = json_str.split('\n')
        processed_lines = []
        for i, line in enumerate(lines):
            line = line.strip()
            if not line:
                continue

            # 如果不是最后一行且当前行以引号结尾且下一行不是结束标记
            if i < len(lines) - 1 and line.rstrip().endswith('"') and not lines[i + 1].strip().startswith('}') and not \
            lines[i + 1].strip().startswith(']'):
                line += ','

            # 如果不是最后一行且当前行以大括号或方括号结尾且下一行不是结束标记
            if i < len(lines) - 1 and (line.rstrip().endswith('}') or line.rstrip().endswith(']')) and not lines[
                i + 1].strip().startswith('}') and not lines[i + 1].strip().startswith(']'):
                line += ','
            if line.__contains__("image") and not line.rstrip().endswith(","):
                line+=','

            if line.__contains__("image") and line.rstrip().endswith(",,"):
                line=line[:-1]
            processed_lines.append(line)

        json_str = '\n'.join(processed_lines)
        # 确保所有属性名都有双引号
        for prop in ['title', 'slides', 'content', 'image_prompt', 'search_query']:
            json_str = json_str.replace(f'{prop}:', f'"{prop}":')
            json_str = json_str.replace(f'"{prop}" :', f'"{prop}":')

        # 确保所有字符串值都有双引号
        import re
        json_str = re.sub(r':\s*([^",\{\[\]\}\s][^",\{\[\]\}\s]*)', r': "\1"', json_str)

        return json_str

    def log_step(message: str):
        """打印生成步骤"""
        print(f"\033[94m[生成进度]\033[0m {message}", file=sys.stderr)

    def get_query(self):
        prompt = f"""
        请根据提供的数据库表结构进行分析，生成一份可视化表单的数据查询列表
        
        数据库表结构如下：
        
        {self.db.get_table_info()}

请严格按照以下JSON格式返回，注意：
1. 所有属性和数组项之间必须用英文逗号分隔
2. 所有字符串必须用英文双引号包裹
3. 不要在JSON中添加任何注释
4. 确保生成的是有效的JSON格式

{{
    "title": "可视化报表的标题",
    "slides": [
        {{
            "title": "每一次查询的模块的主题",
            "detail": "每次查询的问题"
        }}
    ]
}}

内容要求：
1. 查询的列表主题需要丰富，不少于10条
2. 查询的问题需要规范，能够被转化为相应的sql语句
3. 需要严格根据提供的数据库表结构生成回复
4. 内容要专业，数据要准确
        """
        response = self.agent_executor.invoke({
            "input": prompt
        })
        log_step("问题生成完成，开始解析内容...")
        try:
            json_str = self._clean_json_string(response["output"])
            return demjson.decode(json_str)
        except Exception as e:
            print(f"\033[91m[错误]\033[0m JSON解析失败: {str(e)}", file=sys.stderr)
            print(f"\033[93m[调试]\033[0m 原始输出:\n{response['output']}", file=sys.stderr)
            raise

    def get_slide(self, question):
        global json_str
        data = self.query_database(question)

        prompt = f"""
        请根据提供的数据库查询结果，生成一份可视化报表的幻灯片内容。
        
        数据库查询结果如下：
        
        {data}

请严格按照以下JSON格式返回，注意：
1. 所有属性和数组项之间必须用英文逗号分隔,并且只能有一个英文逗号
2. 所有字符串必须用英文双引号包裹
3. 不要在JSON中添加任何注释
4. 确保生成的是有效的JSON格式,一定要确保生成的是有效的JSON格式，一定要确保生成的是有效的JSON格式，一定要确保生成的是有效的JSON格式！！！！！！！特别重要！！！！！
6.image描述需要包含图的结构和内容，内容需要是具体的值，尽可能的详细，方便图像大模型生成
8.在字段属性值中不要出现英文的引号，在字段属性值中不要出现英文的引号
        {{
            "title": "本模块的标题",
            "image":"本张可视化图片的描述，需要尽可能详细,，方便图像大模型生成，只能是条形图，饼状图，扇形图，折线图，柱状图，地图等数学统计图形中的一种",
            "detail": "对本模块的描述，需要尽可能详细，不少于500字，注意在适当的地方分段，内容需要包括数据库查询的结果"
        }}
        """

        response = self.agent_executor.invoke({
            "input": prompt
        })
        log_step("问题生成完成，开始解析内容...")
        try:
            json_str = self._clean_json_string(response["output"])  # ✅ 添加清理逻辑
            json_str = json_str.replace('，', ',')
            json_str = json_str.replace('；', ';')
            json_str = json_str.replace('，', ',')
            json_str = json_str.replace('；', ';') # 替换中文分号 json_str = json_str.replace('，', ',') # 再次确保中文逗号被替换
            jsons = json.loads(json_str)
            jsons["data"] = data
            return jsons
        except Exception as e:
            print(f"\033[91m[错误]\033[0m JSON解析失败: {str(e)}", file=sys.stderr)
            print(f"\033[93m[调试]\033[0m 原始输出:\n{json_str}", file=sys.stderr)
            raise